package com.tedu.api.io;

import org.junit.Test;

import java.io.*;

/**
 * 标准IO流---目的：数据传输 输出文本、图片
 * java定义一套标准流-->数据传输-->
 * 标准流规则①：方向划分 输入流和输出流
 *             输入流：读入--->文件--->相对于程序--->文件往程序里走
 *             InputsStream(抽象类：定义所有读的写法)【学习：子实现类】
 *             输出流：写出--->文件--->相对于程序--->程序写出
 *             OutputsStream(抽象类：定义所有读的写法)【学习：子实现类】
 *         ②：功能划分
 *         低级流【节点流】：是建立在程序与数据之间的“管道”
 *                  功能：负责搬运的数据流，输入流与输出流都有自己的低级流
 *                  特点：一个字节一个字节读或者写的方法
 *              FileOutputStream  低级流继承InputStream---文件输出流
 *              FileInputStream  低级流继承outputStream---文件输入流
 *         高级流：【处理流】：不能直接创建对象，不能独立存在。
 *                    功能：专门处理低级流以及其它高级流的流
 *                    特点：搬运数据时，实现具体功能：效率提高流
 * @author 王培贤
 *  --总结：输出流和输入流，具备功能：低级流与高级流，
 *  实际使用：明确使用具体流，每个流都有自己功能
 */
public class IOAPI {
    /**                                文件输入流
     *              输入流       低级流---
     * 标准流   方向         功能：       文件输出流
     *            输出流        高级流
     * 需求：写出一个文件 fos.txt
     *
     * FileOutputStream  构造器使用
     * new FileOutputStream("路径+文件全称")
     * new FileOutputStream("路径+文件全称",boolean append)
     * 写出文件的同时实现追加效果，第二个参数：true  追加
     *                                  false 默认不追加
     *  new FileOutputStream(File file,boolean append)
     *  写出文件，采用File传入路径+全称
     */
    @Test
    public void testFOS() {
        //置空流
        FileOutputStream fos=null;
//        RandomAccessFile raf=new RandomAccessFile("fos.txt","rw");
        //低级流---文件输出流对象--从程序中写出“文件：数据”
        try {
            fos=new FileOutputStream("fos.txt",true);
            //需求：fos.txt 增加一段文本
            String say="独one无two";
            //字符传由字符数组构成--数组的功能--getBytes()转换为字节数组
            //输出流--写功能：write(byte[] b) 写出字节数组
            fos.write(say.getBytes());
        } catch(FileNotFoundException e){
            e.printStackTrace();
        }
        catch (IOException e) {
            e.printStackTrace();
        } catch(Exception e){
            e.printStackTrace();
        } finally {
            if(fos!=null)
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
        //必须关闭流--目的：节省内存开销
    }
    /**
     * 文件输入流：读入操作
     * FileInputStream 文件输入流
     * read() 返回一个读取的字节--效率低
     * read(字节数组byte[] b)
     * 返回一个“指定字节数组：空间大小”的读取--效率高
     * 需求：读入fos.txt的文件内容
     */
    @Test
    public void testFIS() {
        FileInputStream fis=null;
        //创建文件输入流---读入：fos.txt
        byte[] data= new byte[0];
        int len= 0;
        try {
            fis=new FileInputStream("fos.txt");
            //读入效率高：创建一个字节数组-指定空间为:10KB
            data = new byte[1024*10];
            //读入操作：read(字节数组) | 以10KB读入数据
            len = fis.read(data);
        } catch(FileNotFoundException e){
            e.printStackTrace();
        }
        catch (IOException e) {
            e.printStackTrace();
        } catch(Exception e){
            e.printStackTrace();
        } finally {//关闭流
            if(fis!=null)
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            String str=new String(data,0,len);
            System.out.println("打印fos.txt文件:"+str);
        }
        //写出：文本---字符串--针对流操作，提供构造器
        //                   文件按照“指定字节数组空间”写入程序中
        //                   从0开始写入程序，写到-1结束
        //                   len：十进制转换为二进制进行写入，不等于-1，一直写入
        //一次性将给定的数据按照字节数组指定的空间大小，写出成字符串
    }

    /**
     * 需求：利用标准流实现视频复制粘贴--效率低
     *                              效率高--->空间执行为：自定100KB
     *
     * 【高级流】BufferedInputStream  缓冲输入流--提升效率，内嵌缓冲区：字节数组【长度按照文件大小合理分配】
     *         BufferedOutputStream 缓冲输出流--提升效率，内嵌缓冲区：字节数组【长度按照文件大小合理分配】
     *  高级流使用方式：①处理低级流，套在低级流上
     *               ②直接使用高级流的方法
     *               ③高级流不能直接创建【不能独立存在】
     *
     */
    @Test
    public void testCV() {
        //置空流
        FileInputStream fis=null;
        FileOutputStream fos=null;
        //从“复制文件.mp4” 复制 操作---读入
        long start= 0;
        try {
            fis=new FileInputStream("视频.mp4");
            //2.创建新文件“新文件.mp4” 粘贴 操作---写出
            fos=new FileOutputStream("新文件.mp4",true);
            //3.保存每次读取的数据【字节量--int】
            int len=-1;
            byte[] data=new byte[1024];
            start = System.currentTimeMillis();
            //4.从“复制文件.mp4”进行读入操作，不等于-1 一直读
            // (len=fis.read())!=-1
            while( (len=fis.read(data)) !=-1) {
            //4.1同时 写出“新文件.mp4”
                fos.write(data, 0, len);
            }
        } catch(FileNotFoundException e){
            e.printStackTrace();
        }
        catch (IOException e) {
            e.printStackTrace();
        } catch(Exception e){
            e.printStackTrace();
        } finally {
            if(fis!=null)
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            if(fos!=null)
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            long end=System.currentTimeMillis();
            System.out.println("复制所花费时间：" + (end - start) + "毫秒");
        }
        //5.关闭流  低级流，全部都要关闭 顺序：从上到下，从左到右
    }
    /**
     * 需求：利用标准流实现视频复制粘贴--效率低
     *                              效率高--->空间执行为：自定100KB
     *
     * 【高级流】BufferedInputStream  缓冲输入流--提升效率，内嵌缓冲区：字节数组【长度按照文件大小合理分配】
     *         BufferedOutputStream 缓冲输出流--提升效率，内嵌缓冲区：字节数组【长度按照文件大小合理分配】
     *  高级流使用方式：①处理低级流，套在低级流上
     *               写法：new 高级流(传入低级流引用)
     *               ②直接使用高级流的方法
     *               ③高级流不能直接创建【不能独立存在】
     */
    @Test
    public void testCVS() {
        //置空流
        FileInputStream fis=null;
        BufferedInputStream bis=null;
        FileOutputStream fos=null;
        BufferedOutputStream bos=null;
        //1.创建低级流：读入“视频.mp4”
        long start= 0;
        try {
            fis=new FileInputStream("视频.mp4");
            //1.创建一个高级流：套在低级流上【自带缓冲区：字节数组】
            bis=new BufferedInputStream(fis);
            //2.创建低级流：写出“高效的视频.mp4”
            fos=new FileOutputStream("高效的视频.mp4");
            //2.创建高级流：套在低级流上【自带缓冲区：字节数组】
            bos=new BufferedOutputStream(fos);
            //3.保存每次读取的数据【字节量--int】
            int len=-1;
            //记录程序开始时间
            start = System.currentTimeMillis();
            //4.高级流--低级流方法一致---read()读取内嵌缓冲区【字节数组】
            //4.从“视频.mp4”进行读入操作，不等于-1 一直读
            // (len=fis.read())!=-1
            while( (len=bis.read()) !=-1) {
                //4.1同时 写出“新文件.mp4”
                bos.write(len);
            }
        } catch(FileNotFoundException e){
            e.printStackTrace();
        }
        catch (IOException e) {
            e.printStackTrace();
        } catch(Exception e){
            e.printStackTrace();
        } finally {
            if(bis!=null)//高级流--缓冲输入流
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            if(bos!=null)//高级流--缓冲输出流
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            //记录程序结束时间
            long end=System.currentTimeMillis();
            //输出复制所花费时间
            System.out.println("复制所花费时间：" + (end - start) + "毫秒");
        }
        //5.关闭流  高级流和低级流，全部都要关闭 顺序：从上到下，从左到右  原则上先关高级流，有高级流和低级流
        //关低级流即可
    }
    /**
     * 高级流：--缓冲区【内嵌缓冲区】
     * BufferedOutputStream  缓冲输出流
     *
     * 需求：通过缓冲输出流实现从程序写出文件：bos.txt，写出内容
     */
    @Test
    public void testBOS() {
        //置空流
        FileOutputStream fos=null;
        BufferedOutputStream bos=null;
        //1.创建低级流-->bos.txt
        try {
            fos=new FileOutputStream("bos.txt");
            //2.创建一个高级流，具备缓冲区特点：字节数组--合理【传输效率】
            bos=new BufferedOutputStream(fos);
            //3.写出一个文件的文本内容
            String str="50 块钱设计的再好看，也不如100块钱招人稀罕~~~";
            //4.写出到 bos.txt 文件中  字符串转为字节数组--写出
            bos.write(str.getBytes());
            //5.将缓冲区数据一次性写出 flush() 【立即写出】
            bos.flush();
        } catch(FileNotFoundException e){
            e.printStackTrace();
        }
        catch (IOException e) {
            e.printStackTrace();
        } catch(Exception e){
            e.printStackTrace();
        } finally {
            if(fos!=null)
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            if(bos!=null)
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
        //fos.close();
        //bos.close();  //关闭流--一定会把缓冲区数据全部写出【只有缓冲流才有这样的特点】
    }
    /**
     * 标准IO--成对【高级流+低级流】结合异常--数据传输--一定要成功【异常需要捕获】
     * 需求：重构 testBOS() 单元测试
     */
    @Test
    public void testBOSIO(){
        //1.置空流---提升所有流的作用域
        FileOutputStream fos=null;//低级流:搬运数据
        BufferedOutputStream bos=null;//高级流:缓冲输出流
        //2.捕获流的异常并且做出处理
        try {
            fos=new FileOutputStream("bos.txt");//低级流  FileOutputStream文件不存在异常
            bos=new BufferedOutputStream(fos);//高级流
            bos.write("我是初音未来的狗！！！".getBytes());  //中异常：IOException【IO异常】
            bos.flush();
        } catch(FileNotFoundException e){//IO流”小“异常
            e.printStackTrace();
        }
        catch (IOException e) { //IO流”中“异常：小异常父类
            e.printStackTrace();
        } catch(Exception e){//“大”异常 Exception
            e.printStackTrace();
        }
        finally {
            //3.关闭流---高级流---释放资源
            //判断：高级流是否为空，高级流不为null，关闭
            if(bos!=null)
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }
}
